#region Imported Namespaces

using System;
using System.Data;
using System.Collections;
using System.Data.SqlClient;
using PHSRAG.Insight21.InsightUtilities;
using System.Text;

using BO				= PHSRAG.Insight21.BusinessObjects;
using DataAccess		= PHSRAG.Utility.DataAccess;
using ICachePolicy		= PHSRAG.Insight21.Policy.ICachePolicy;
using SearchCriteria	= PHSRAG.Insight21.SearchContext.SearchCriteria;

#endregion

namespace PHSRAG.Insight21.Purchasing
{
	#region Class UserOrderSummaries
	/// <summary>
	/// The UserOrderSummaries object supports loading of summary information
	/// for all user orders to which the user has access. It also exposes methods to 
	/// support sorting and searching on the retrieved data.
	/// </summary>
	public class UserOrderSummaries : BO.BusinessObject
	{
		#region Constants
		private const string	DefaultSortColumn			= "OrderDate";
		private const string	UserOrderSummaryStoreProc	= "GetUserOrderSummary";
		private const int		SummaryDataTableIndex		= 0;
		#endregion

		#region Enums (Private)
		private enum ArgumentIndex
		{
			SearchCriteria,
			Count
		}
		#endregion

		#region Instance Variables
		private Hashtable		userOrderSummaryMap		= new Hashtable();
		private string			currentDataTableName	= Constants.OriginalDataTableName;
		private bool			sortAscending			= false;
		private string			sortColumn				= DefaultSortColumn;
		#endregion

		#region Constructor
		/// <summary>
		/// Constructor, simply initilize the base class by passing cachePolicy.
		/// </summary>
		/// <param name="cachePolicy">cache policy used to maintain the state of business object</param>
		public UserOrderSummaries(ICachePolicy cachePolicy) : base(cachePolicy)
		{
		}
		#endregion

		#region Public Properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return Constants.UserOrderSummariesKey; } }
		/// <summary>
		/// Get the total number of UserOrder Transactions.
		/// </summary>
		public int Count
		{
			get { return (DataContainer.Tables.Count == 0) ? 0 : DataContainer.Tables[currentDataTableName].Rows.Count; }
		}		  
		/// <summary>
		/// Get the sort sequence.
		/// </summary>
		public bool SortAscending
		{
			get { return sortAscending; }
		}
		/// <summary>
		/// Get the name of the sort column.
		/// </summary>
		public string SortColumn
		{
			get { return sortColumn; }
		}
		/// <summary>
		/// Get the table name of the active table in the data container
		/// This will be used for selective downloading of data into reports
		/// </summary>
		public string CurrentDataTableName
		{
			get { return currentDataTableName;}
		}
		#endregion

		#region BusinessObject Methods
		/// <summary>
		/// Cache the current instance using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(CacheKey, this);
		}
		/// <summary>
		/// Remove the current instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(CacheKey);
		}
		/// <summary>
		/// Load the user order summary data for the current user and set the datatable name
		/// Sort the loaded data on the default sort column
		/// For the load the domain user id,transactionfrom date and to date are mandatory.
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">Is expected to contain the search criteria object.</param>
		public override void Load(string connectionString, params object[] args)
		{
			if (args.Length != (int)ArgumentIndex.Count)
				throw new Exception(string.Format
					("User Order load requires {0} arguments",((int)ArgumentIndex.Count).ToString()));

			if (args[0] == null )
				throw new Exception("User Order Summaries load requires Search Criteria containing at least a domain user ID");

			SearchCriteria commonSearchCriteria = (SearchCriteria) args[0];

			DataContainer  = DataAccess.GetDataSet(
				connectionString
				,UserOrderSummaryStoreProc
				,DataAccess.BuildSqlParameterArray (
				"@domainUserID", 			SqlDbType.Int,		commonSearchCriteria[InsightUtilities.Constants.DomainUserIDKey],
				"@transactionDateFrom",		SqlDbType.DateTime, commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.TransactionDateFromKey],
				"@transactionDateTo",		SqlDbType.DateTime,	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.TransactionDateToKey],
				"@fundNumber", 				SqlDbType.VarChar, 	commonSearchCriteria[InsightUtilities.Constants.FundIDKey],
				"@accountNumber", 			SqlDbType.VarChar,	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.AccountNumberKey],
				"@accountCategoryId", 		SqlDbType.Int, 		commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.CategoryIdKey],
				"@invoiceNumber",  			SqlDbType.VarChar, 	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.InvoiceNumberKey],
				"@invoiceDate",				SqlDbType.DateTime, commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.InvoiceDateKey],
				"@poNumber", 				SqlDbType.VarChar, 	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.PONumberKey],
				"@voucherNumber", 			SqlDbType.VarChar, 	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.VoucherNumberKey],
				"@requestorName", 			SqlDbType.VarChar,	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.RequestorNameKey],				
				"@requisitionNumber", 		SqlDbType.VarChar,	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.RequisitionNumberKey],
				"@vendorName",				SqlDbType.VarChar, 	commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.VendorNameKey],
				"@orderTypeID",				SqlDbType.Int,		commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.UserOrderTypeViewKey],
				"@piID",					SqlDbType.Int,		commonSearchCriteria[InsightUtilities.Constants.PIIDKey],
				"@chiefCodeList",			SqlDbType.VarChar,	commonSearchCriteria.COSIds,
                "@amount", SqlDbType.Money, commonSearchCriteria[InsightUtilities.Constants.PurchasingSearchKey.TotalOrderAmountKey]

				));

			if(DataContainer.Tables.Count ==1)                                
				DataContainer.Tables[SummaryDataTableIndex].TableName = Constants.OriginalDataTableName;
			else
				throw new Exception("Error in Executing UserOrder Summaries StoreProc");

		}
		#endregion
		
		#region Public methods
		/// <summary>
		/// Get the list of UserOrder objects bound by a start and end index. These indeces are into the list of UserOrder
		/// summaries that was loaded during the Load() method execution into the data container. Typically, the start index
		/// is on a "page" boundary, where the "page" referes to a datagrid page.
		/// Note that the total number of UserOrder objects returned may be less than the requested count.
		/// We maintain a Hashtable of ArrayList objects using the start index as the key. This allows us to retrieve the
		/// set of UserOrder objects associated with that index, thereby directly supporting random access based the
		/// page index.
		/// If such an ArrayList does not exist for the current page index, we load them using the list of UserOrder IDs.
		/// The start end end indeces into that list are computed based on the current page index and the datagrid page size.
		/// UserOrder objects are loaded based on the summaries which falls within the compute start and end indeces, 
		/// and saved in an ArrayList. That ArrayList is then stored in the Hashtable with the current page index as its
		/// key.
		/// </summary>
		/// <param name="startIndex">Index within the UserOrder summary list to begin at</param>
		/// <param name="count">Total number of UserOrder objects to load</param>
		/// <returns>The list of UserOrder objects</returns>
		public ArrayList GetUserOrderSummaryList(int startIndex, int count)
		{
			ArrayList orderList = userOrderSummaryMap[startIndex] as ArrayList;
			if (orderList == null)
			{
				orderList = new ArrayList();
				DataTable dataTable = DataContainer.Tables[currentDataTableName];
				for (int indexCount = startIndex, end = Math.Min(indexCount + count, dataTable.Rows.Count); indexCount < end; ++indexCount)
					orderList.Add(new UserOrderSummary(CachePolicy, dataTable.Rows[indexCount]));
				userOrderSummaryMap[startIndex] = orderList;
			}
			return orderList;
		}
		
		/// <summary>
		/// Sort the list of user order summaries by the speicified column.
		/// If the column is to be sorted is the same as what was last sorted on, the sort sequence is toggled. Else, the
		/// sort sequence is set to ascending.
		/// </summary>
		/// <param name="columnName">Column to sort by</param>
		public void Sort(string columnName)
		{
			userOrderSummaryMap.Clear();

			sortAscending = (sortColumn == columnName) ? !sortAscending : true;
			sortColumn = columnName;

			ProcessSort();
		}
		#endregion

		#region Private methods
		/// <summary>
		/// Sorts the current data table on the sortColumn instance variable
		/// in the order specified by the sortOrder instance variable
		/// </summary>
		private void ProcessSort()
		{
			DataTable summaryTable = DataContainer.Tables[currentDataTableName];
			DataView summaryView = summaryTable.DefaultView;
			summaryView.Sort = string.Format("{0} {1}", 
				sortColumn, sortAscending ? Constants.SortOrderAscending : Constants.SortOrderDescending);

			DataTable sortedDataTable = summaryTable.Clone();
			foreach (DataRowView summaryRowView in summaryView)
				sortedDataTable.ImportRow(summaryRowView.Row);

			if(DataContainer.Tables.Contains(currentDataTableName))
				DataContainer.Tables.Remove(currentDataTableName);
			
			DataContainer.Tables.Add(sortedDataTable);
		}
		/// <summary>
		/// Get the COS IDs from the list of Name:ID pairs
		/// </summary>
		/// <param name="cos">COS Name ID List "Name:ID|Name1:ID1"</param>
		/// <returns>Comma seperated list of IDs</returns>
		private string GetCOSIDList(string cos)
		{
			string[] cosIDs = cos.Split(new Char[] {':','|'});
			StringBuilder cosIDList = new StringBuilder();			
			for(int i = 0;i<=cosIDs.Length;i++)
			{
				if((i%2) != 0)
					cosIDList.AppendFormat("{0},",cosIDs[i]);
			}			
			return string.Format("({0})",cosIDList.ToString().TrimEnd(','));
		}
		/// <summary>
		/// Add a table with distinct rows to the data container
		/// </summary>
		/// <param name="summaryTable">datatable with user order summary data,
		/// from which distinct rows will be picked</param>
		private void AddTableWithDistinctRows(DataTable summaryTable)
		{
			DataTable distinctTable		= summaryTable.Clone();
			distinctTable.TableName		= currentDataTableName = Constants.FilteredDataTableName;

			if(summaryTable.Rows.Count >= 1)
			{
				foreach (DataRow summaryRow in summaryTable.Rows)
				{
					// If a row with the same OrderID, FundNumber and Requestor name effective
					// is in the distinct table, ignore row, otherwise import
					if (distinctTable.Select(string.Format("{0} = '{1}' AND {2} = '{3}' AND {4} = '{5}'",
						Constants.OrderIDColumnName,
						summaryRow[Constants.OrderIDColumnName],
						Constants.PurchasingFundNumberColName,
						summaryRow[Constants.PurchasingFundNumberColName],
						Constants.PurchasingRequestorNameColName,
						((string)summaryRow[Constants.PurchasingRequestorNameColName]).Replace("'","''"))).Length == 0)
					{
						distinctTable.ImportRow(summaryRow);
					}
				}
			}						
			if(DataContainer.Tables.Contains(currentDataTableName))
				DataContainer.Tables.Remove(currentDataTableName);
			DataContainer.Tables.Add(distinctTable);

			ProcessSort();
		}
		#endregion
	}
	#endregion
}
// --- EOF ---